package com.automapper.execute;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

import com.automapper.constants.EnumAction;
import com.automapper.execute.impl.BaseExecute;
import com.automapper.execute.impl.PersistentExecute;
import com.automapper.execute.impl.SelectExecute;
import com.automapper.execute.impl.UpdateRouterExecute;
import com.automapper.sqlbuilder.impl.DeleteSqlBuilder;
import com.automapper.sqlbuilder.impl.InsertRouterSqlBuilder;
import com.automapper.sqlbuilder.impl.InsertSqlBuilder;
import com.automapper.sqlbuilder.impl.SelectRouterSqlBuilder;
import com.automapper.sqlbuilder.impl.UpdateSqlBuilder;

public class ExecuteFactory {
	
	private static Map<String, Execute> instanceMap = new HashMap<>();
	private static Map<String, Class<?>> factoryMap = new HashMap<>();
	private static Map<String, Class<?>> sqlBuilderMap = new HashMap<>();
		
	static {	
		factoryMap.put(EnumAction.INSERT.getKey(), BaseExecute.class);
		factoryMap.put(EnumAction.UPDATE.getKey(), UpdateRouterExecute.class);
		factoryMap.put(EnumAction.DELETE.getKey(), BaseExecute.class);
		factoryMap.put(EnumAction.PERSISTENT.getKey(), PersistentExecute.class);
		factoryMap.put(EnumAction.SELECT.getKey(), SelectExecute.class);
		//insert使用InsertRouterSqlBuilder是因为根据参数类型使用不同处理方式入库操作
		//当传入参数为Map类型是，使用InsertMapSqlBuilder
		//当传入参数为非Map类型是，使用InsertSqlBuilder
		sqlBuilderMap.put(EnumAction.INSERT.getKey(), InsertRouterSqlBuilder.class);
		sqlBuilderMap.put(EnumAction.UPDATE.getKey(), UpdateSqlBuilder.class);
		sqlBuilderMap.put(EnumAction.DELETE.getKey(), DeleteSqlBuilder.class);
		sqlBuilderMap.put(EnumAction.PERSISTENT.getKey(), InsertSqlBuilder.class);
		// select使用SelectRouterSqlBuilder是因为根据参数类型使用不同处理方式入库操作
		// 当传入参数为fetch_mode = ASSOCIATION_PAGE_BY_PARENT使用SelectAssociationPageByParentSqlBuilder
		// 当传入参数为fetch_mode = DEFAULT是，使用SelectSqlBuilder
		sqlBuilderMap.put(EnumAction.SELECT.getKey(), SelectRouterSqlBuilder.class);
	}
	
	private ExecuteFactory(){}

	public static Execute getInstance(String key) throws Exception {
		if (instanceMap.containsKey(key)) {
			return instanceMap.get(key);
		}
		
		Object object = factoryMap.get(key).newInstance();
		setFieldValue(object, sqlBuilderMap.get(key));
		instanceMap.put(key, (Execute) object);
		return (Execute) object;
	}
	
	private static void setFieldValue(Object object, Class<?> clazz) throws Exception {
		Field[] fields = object.getClass().getDeclaredFields();
		for (Field field : fields) {
			Class<?> fieldClazz = field.getType();
			if (fieldClazz.toString().equals(clazz.getSuperclass().toString())) {
				field.setAccessible(true);
				field.set(object, clazz.newInstance());
				break;
			}
		}
	}
}
